#pragma once

#include <iostream>
#include <string>
#include <cstring>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define SPACE " "
#define SPACE_LEN strlen(SPACE)

#define SEP "\r\n"
#define SEP_LEN strlen(SEP)

class Request
{
public:
    Request() {}

    Request(int x, int y, char op)
        :_x(x)
        ,_y(y)
        ,_op(op)
    {}

    std::string Serialize()
    {
        std::string str;
        str = std::to_string(_x);
        str += SPACE;
        str += _op;
        str += SPACE;
        str += std::to_string(_y);
        return str;
    }

    bool Deserialized(const std::string& str)
    {
        std::size_t left = str.find(SPACE);
        if (left == std::string::npos)
            return false;
        std::size_t right = str.rfind(SPACE);
        if (right == std::string::npos)
            return false;
        _x = atoi(str.substr(0, left).c_str());
        _y = atoi(str.substr(right + SPACE_LEN).c_str());
        if (left + SPACE_LEN > str.size()) return false;
        _op = str[left+ SPACE_LEN];

        return true;
    }

    ~Request() {}
public:
    int _x;
    int _y;
    char _op;
};

class Respense
{
public:
    Respense() {}

    Respense(int result, int code, int x, int y, char op)
        :_result(result)
        ,_code(code)
        ,_x(x)
        ,_y(y)
        ,_op(op)
    {}

    std::string Serialize()
    {
        std::string s;
        s += std::to_string(_code);
        s += SPACE;
        s += std::to_string(_result);

        return s;
    }

    bool Deserialized(const std::string& s)
    {
        std::size_t pos = s.find(SPACE);
        if (pos == std::string::npos)   return false;
        _code = atoi(s.substr(0, pos).c_str());
        _result = atoi(s.substr(pos + SPACE_LEN).c_str());
        return true;
    }

    ~Respense() {}
public:
    int _result;
    int _code;

    int _x;
    int _y;
    char _op;
};

bool Recv(int sock, std::string* out)
{
    char buffer[1024];
    ssize_t s = recv(sock, buffer, sizeof(buffer) - 1, 0);
    if (s > 0)
    {
        buffer[s] = 0;
        *out = buffer;
    }
    else if (s == 0)
    {
        std::cout << "client quit" << std::endl;
        return false;
    }
    else
    {
        std::cout << "recv error" << std::endl;
        return false;
    }

    return true;
}

void Send(int sock, const std::string str)
{
    int n = send(sock, str.c_str(), str.size(), 0);
    if (n < 0)
        std::cout << "send error" << std::endl;
}

std::string DeCode(std::string& buffer)
{
    std::size_t pos = buffer.find(SEP);
    if (pos == std::string::npos) return "";
    int size = atoi(buffer.substr(0, pos).c_str());
    int surplus = buffer.size() - pos - 2 * SEP_LEN;
    if (surplus >= size)
    {
        // 至少有一个合法的报文了
        buffer.erase(0, pos + SEP_LEN);
        std::string s = buffer.substr(0, size);
        buffer.erase(0, size + SEP_LEN);
        return s;
    }
    else
    {
        return "";
    }
}

std::string EnCode(std::string& s)
{
    std::string new_package = std::to_string(s.size());
    new_package += SEP;
    new_package += s;
    new_package += SEP;
    return new_package;
}
